<commit_before>'use babel'
/** @jsx etch.dom */

import etch from 'etch'
import os from 'os'
import {CompositeDisposable} from 'atom'
import DebugEngine from './engines/dbgp/engine'
import DecoratorService from './services/decorator'
import StatusBarDebugView from './status/debug-view'
import StatusBarConsoleView from './status/console-view'
import DefaultBreakpointsView from './breakpoints/default-breakpoints-view'
class PHPDebug {
  constructor() {
  }
  activate(state) {
    this._subscriptions = new CompositeDisposable();
    this._engine = new DebugEngine()
    this.showUpgradeNotice()
    this.requirePackages()
    this._state = this.deserialize(state);
    this.registerSubscriptions();
  }

  registerSubscriptions() {
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:run': (event) => {
        if (this._engine != undefined && this._engine != null) {
          let context = this._engine.tryGetContext()
          if (context != null) {
            context.executeRun();
          }
        }
      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepOver': (event) => {

      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepIn': (event) => {

      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepOut': (event) => {

      }
    }));
  }

  showUpgradeNotice() {
    const showWelcome = atom.config.get('php-debug.showWelcome')
    if (!showWelcome) {
      return
    }
    const notification = atom.notifications.addInfo('php-debux', {
        dismissable: true,
        icon: 'bug',
        detail: 'Welcome to the new PHP-Debug! Check out some of the new Features:\n* Multiple Debugging Sessions\n* Cleaner UI\n* Overlay Debugging Command Bar\n* Tool tips for variables while debugging',
        description: 'Many of your previous settings may have changes or may no longer be available. You will likely need to reconfigure the package.',
        buttons: [{
          text: 'Open Settings Now',
          onDidClick: () => {
            notification.dismiss()
            atom.config.set('php-debug.showWelcome', false)
            this.openSettingsView()
          }
        },{
          text: 'Got It',
          onDidClick: () => {
            notification.dismiss()
            atom.config.set('php-debug.showWelcome', false)
          }
        }, {
          text: 'Remind Me Next Time',
          onDidClick: () => {
            notification.dismiss()
          }
        }]
      })
  }

  openSettingsView() {
    atom.workspace.open('atom://config/packages/php-debug')
  }

  requirePackages() {
    const pkg = 'atom-debug-ui'
    const detail = 'It provides IDE/UI features for debugging inside atom'
    const packages = new Map()
    packages.set("atom-debug-ui",{required:true,details:'It provides IDE/UI features for debugging inside atom'})
    packages.set("ide-php",{required:false,details:'It provides IDE features for PHP'})
    packages.set("atom-ide-ui",{required:false,details:'It provides IDE features for Atom that will be used by ide-php'})
    for (let [pkg, info] of packages) {

      const existingPkg = atom.packages.getLoadedPackage(pkg)
      if (existingPkg != null) continue

      const notification = atom.notifications.addInfo('php-debug', {
        dismissable: true,
        icon: 'cloud-download',
        detail: 'This package '+ (info.required ? 'requires' : 'works better with') + ' the ' + pkg + ' package. ' + info.details,
        description: 'Would you like to install **' + pkg + '**?' + (info.required ? ' **It is _required_ for this plugin to work.**' : ''),
        buttons: [{
          text: 'Yes',
          onDidClick: () => {
            notification.dismiss()
            this.installPkg(pkg)
          }
        }, {
          text: 'Not Now',
          onDidClick: () => {
            notification.dismiss()
          }
        }, {
          text: 'Never',
          onDidClick: () => {
            notification.dismiss()
            const disabledBundledPackages = atom.config.get('php-debug.noPackageInstallPrompt')
            if (!disabledBundledPackages.includes(pkg)) {
              disabledBundledPackages.push(pkg)
              atom.config.set('php-debug.noPackageInstallPrompt', disabledBundledPackages)
            }
          }
        }]
      })
    }
  }

  installPkg(pkg) {
    console.debug(`Attempting to install installing package ${pkg}`)
    const p = atom.packages.activatePackage('settings-view')
    if (!p) {
      return
    }
    p.then( (settingsPkg) => {
    if (!settingsPkg  || !settingsPkg.mainModule) {
       console.warn("Could not find settings view")
       return
    }
    const settingsview = settingsPkg.mainModule.createSettingsView({uri: settingsPkg.mainModule.configUri})
      settingsview.packageManager.install({name: pkg}, (error) => {
        if (!error) {
          console.info(`The ${pkg} package has been installed`)
          atom.notifications.addInfo(`Installed the ${pkg} package`)
        } else {
          let content = ''
          if (error.stdout) {
            content = error.stdout
          }
          if (error.stderr) {
            content = content + os.EOL + error.stderr
          }
          content = content.trim()
          atom.notifications.addError(content)
          console.error(error)
        }
      })
    }).catch( (err) => {
      console.warn("Could not find settings view package",err)
    })
  }

  provideDebugEngineService() {
    if (this._engine.isDestroyed) {
      this._engine = new DebugEngine()
    }
    return this._engine
  }

  consumeDebugUI(services) {
    try {
      if (this._services != undefined || this._services != null) {
        this._services.destroy()
        this._subscriptions.dispose()
        this._subscriptions = new CompositeDisposable()
      }
      this._services = services
      this._engine.setUIServices(services)
      this._services.activate(this._engine.getName(), this._state.services)
      this._subscriptions.add(this._services.onServiceRegistered(this.serviceRegistered.bind(this)))
      this._services.registerService('Decorator',new DecoratorService(this._services,{}))
      this._services.requestService('actions',{},this.actionsServiceActivated.bind(this))
      this._services.requestService('stack')
      this._services.requestService('console')
      this._services.requestService('status')
      this._services.requestService('scope')
      this._services.requestService('watches')
      //xDebug does not support watchpoints
      //this._services.requestService('watchpoints')
      const view = <DefaultBreakpointsView services="{this._services}" />
      const breakpointsOptions = {
        attachedViews: view
      }
      this._services.requestService('breakpoints',breakpointsOptions)
      const viewOptions = {
        allowDefaultConsole: true,
        allowDefaultDebugger: true,
        uriPrefix:'php-debug',
        debugViewTitle:'PHP Debug',
        consoleViewTitle:'PHP Console',
        combineBreakpointsWatchpoints: false
      }
      this._services.requestService('debugview',viewOptions,this.debugViewServiceActivated.bind(this))
      this._services.getLoggerService().info("Received Debug UI Services")
    } catch (err) {
      atom.notifications.addError(`Failed to load PHP-Debug`, {
        detail: err,
        dismissable: true
      })
      throw err
    }
  }

  getGrammarScopes() {
     return ['text.html.php'];
  }

  consumeDatatip(service) {
    let provider = {
      providerName: "PHPDebugLanguageClient",
      priority: 12,
      grammarScopes: this.getGrammarScopes(),
      validForScope: (scopeName) => {
        return this.getGrammarScopes().includes(scopeName)
      },
      datatip: this.getDatatip.bind(this)
    }
    service.addProvider(provider);
  }

  getDatatip(tipEditor, tipPoint) {
    return new Promise((resolve,reject) => {
      if (this._engine == undefined || this._engine == null) {
        reject();
        return;
      }
      let pkg = atom.packages.getActivePackage("ide-php")
      if (pkg == undefined || pkg == null) {
        reject();
        return;
      }
      pkg.mainModule.getDatatip(tipEditor,tipPoint).then((result) => {
        let editor = atom.workspace.getActivePaneItem();
        if (editor == undefined || editor == null || editor.getTextInBufferRange == undefined || result == undefined || result == null) {
          reject();
          return;
        } else {
          let highlight = editor.getTextInBufferRange(result.range);
          let debugContext = this._engine.tryGetContext();
          if (debugContext == undefined || debugContext == null) {
            reject();
            return;
          }
          if (highlight == undefined || highlight == null) {
            reject();
            return;
          } else {
            let p = debugContext.evalExpression(highlight)
            p.then((data) => {
              let markedString = {
                grammar: editor.getGrammar(),
                type: "snippet",
                value: "\"" + data + "\""
              }
              if (result.markedStrings != undefined && result.markedStrings != null) {
                result.markedStrings = [];
                result.markedStrings.push(markedString);
              }
              resolve(result)
              return;
            });
          }
        }
      }).catch((error) => {
        reject(error);
        return;
      });
    });
  }

  debugViewServiceActivated(service,options) {
    this._subscriptions.add(service.onDefaultDebuggerRequested(() => {
      this._engine.createDebuggingContext("default").then( (context) => {
        const uiService = context.getUIService()
        if (uiService != null) {
          uiService.activateDebugger()
        }
      })
    }))
    this._subscriptions.add(service.onDefaultConsoleRequested(() => {
      this._engine.createDebuggingContext("default").then( (context) => {
        const uiService = context.getUIService()
        if (uiService != null) {
          uiService.activateDebugger()
        }
      })
    }))
    this._subscriptions.add(service.onContextCreated(this.debugContextViewServiceCreated.bind(this)))
  }

  actionsServiceActivated(service,options) {
    service.hideActionButtons(['attach','run'])
  }

  debugContextViewServiceCreated(event) {
    event.service.enablePanels(['watches','breakpoints','context','stack'])
  }

  serviceRegistered(event) {
    this._services.getLoggerService().info('Service registered: ' + event.name)
  }

  consumeStatusBar (statusBar) {
    this._subscriptions.add(atom.config.observe("php-debug.display.enableStatusbarButtons", (enable) => {
      if (enable) {
        this._debugView = new StatusBarDebugView({statusBar:statusBar, engine:this._engine})
        this._consoleView = new StatusBarConsoleView({statusBar:statusBar, engine:this._engine})
      }
      else {
        if (this._consoleView != undefined && this._consoleView != null) {
          this._consoleView.destroy()
          delete this._consoleView
        }
        if (this._debugView != undefined && this._debugView != null) {
          this._debugView.destroy()
          delete this._debugView
        }
      }
    }))
  }

  deactivate() {
    if (this._engine != undefined && this._engine != null) {
      this._engine.destroy()
      delete this._services
    }
    if (this._service != undefined && this._engine != null) {
      this._services.destroy()
      delete this._services
    }
    this._subscriptions.dispose()
    delete this._subscriptions
  }

  serialize() {
    if (this._services != undefined && this._services != null) {
      var results = {
        "deserializer": "PHPDebug",
        "data": {
          "services" : this._services.serialize()
        }
      }
      return results;
    }
    return {};
  }
  deserialize(state) {
    if (state != null) {
      if (typeof state.data === "object") {
        return state.data;
      } else {
        return {"services":null}
      }
    }
  }
}
atom.deserializers.add(PHPDebug);
module.exports = new PHPDebug()
<commit_msg>Fix typo in notification<commit_after>'use babel'
/** @jsx etch.dom */

import etch from 'etch'
import os from 'os'
import {CompositeDisposable} from 'atom'
import DebugEngine from './engines/dbgp/engine'
import DecoratorService from './services/decorator'
import StatusBarDebugView from './status/debug-view'
import StatusBarConsoleView from './status/console-view'
import DefaultBreakpointsView from './breakpoints/default-breakpoints-view'
class PHPDebug {
  constructor() {
  }
  activate(state) {
    this._subscriptions = new CompositeDisposable();
    this._engine = new DebugEngine()
    this.showUpgradeNotice()
    this.requirePackages()
    this._state = this.deserialize(state);
    this.registerSubscriptions();
  }

  registerSubscriptions() {
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:run': (event) => {
        if (this._engine != undefined && this._engine != null) {
          let context = this._engine.tryGetContext()
          if (context != null) {
            context.executeRun();
          }
        }
      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepOver': (event) => {

      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepIn': (event) => {

      }
    }));
    this._subscriptions.add(atom.commands.add('atom-workspace', {
      'php-debug:stepOut': (event) => {

      }
    }));
  }

  showUpgradeNotice() {
    const showWelcome = atom.config.get('php-debug.showWelcome')
    if (!showWelcome) {
      return
    }
    const notification = atom.notifications.addInfo('php-debug', {
        dismissable: true,
        icon: 'bug',
        detail: 'Welcome to the new PHP-Debug! Check out some of the new Features:\n* Multiple Debugging Sessions\n* Cleaner UI\n* Overlay Debugging Command Bar\n* Tool tips for variables while debugging',
        description: 'Many of your previous settings may have changes or may no longer be available. You will likely need to reconfigure the package.',
        buttons: [{
          text: 'Open Settings Now',
          onDidClick: () => {
            notification.dismiss()
            atom.config.set('php-debug.showWelcome', false)
            this.openSettingsView()
          }
        },{
          text: 'Got It',
          onDidClick: () => {
            notification.dismiss()
            atom.config.set('php-debug.showWelcome', false)
          }
        }, {
          text: 'Remind Me Next Time',
          onDidClick: () => {
            notification.dismiss()
          }
        }]
      })
  }

  openSettingsView() {
    atom.workspace.open('atom://config/packages/php-debug')
  }

  requirePackages() {
    const pkg = 'atom-debug-ui'
    const detail = 'It provides IDE/UI features for debugging inside atom'
    const packages = new Map()
    packages.set("atom-debug-ui",{required:true,details:'It provides IDE/UI features for debugging inside atom'})
    packages.set("ide-php",{required:false,details:'It provides IDE features for PHP'})
    packages.set("atom-ide-ui",{required:false,details:'It provides IDE features for Atom that will be used by ide-php'})
    for (let [pkg, info] of packages) {

      const existingPkg = atom.packages.getLoadedPackage(pkg)
      if (existingPkg != null) continue

      const notification = atom.notifications.addInfo('php-debug', {
        dismissable: true,
        icon: 'cloud-download',
        detail: 'This package '+ (info.required ? 'requires' : 'works better with') + ' the ' + pkg + ' package. ' + info.details,
        description: 'Would you like to install **' + pkg + '**?' + (info.required ? ' **It is _required_ for this plugin to work.**' : ''),
        buttons: [{
          text: 'Yes',
          onDidClick: () => {
            notification.dismiss()
            this.installPkg(pkg)
          }
        }, {
          text: 'Not Now',
          onDidClick: () => {
            notification.dismiss()
          }
        }, {
          text: 'Never',
          onDidClick: () => {
            notification.dismiss()
            const disabledBundledPackages = atom.config.get('php-debug.noPackageInstallPrompt')
            if (!disabledBundledPackages.includes(pkg)) {
              disabledBundledPackages.push(pkg)
              atom.config.set('php-debug.noPackageInstallPrompt', disabledBundledPackages)
            }
          }
        }]
      })
    }
  }

  installPkg(pkg) {
    console.debug(`Attempting to install installing package ${pkg}`)
    const p = atom.packages.activatePackage('settings-view')
    if (!p) {
      return
    }
    p.then( (settingsPkg) => {
    if (!settingsPkg  || !settingsPkg.mainModule) {
       console.warn("Could not find settings view")
       return
    }
    const settingsview = settingsPkg.mainModule.createSettingsView({uri: settingsPkg.mainModule.configUri})
      settingsview.packageManager.install({name: pkg}, (error) => {
        if (!error) {
          console.info(`The ${pkg} package has been installed`)
          atom.notifications.addInfo(`Installed the ${pkg} package`)
        } else {
          let content = ''
          if (error.stdout) {
            content = error.stdout
          }
          if (error.stderr) {
            content = content + os.EOL + error.stderr
          }
          content = content.trim()
          atom.notifications.addError(content)
          console.error(error)
        }
      })
    }).catch( (err) => {
      console.warn("Could not find settings view package",err)
    })
  }

  provideDebugEngineService() {
    if (this._engine.isDestroyed) {
      this._engine = new DebugEngine()
    }
    return this._engine
  }

  consumeDebugUI(services) {
    try {
      if (this._services != undefined || this._services != null) {
        this._services.destroy()
        this._subscriptions.dispose()
        this._subscriptions = new CompositeDisposable()
      }
      this._services = services
      this._engine.setUIServices(services)
      this._services.activate(this._engine.getName(), this._state.services)
      this._subscriptions.add(this._services.onServiceRegistered(this.serviceRegistered.bind(this)))
      this._services.registerService('Decorator',new DecoratorService(this._services,{}))
      this._services.requestService('actions',{},this.actionsServiceActivated.bind(this))
      this._services.requestService('stack')
      this._services.requestService('console')
      this._services.requestService('status')
      this._services.requestService('scope')
      this._services.requestService('watches')
      //xDebug does not support watchpoints
      //this._services.requestService('watchpoints')
      const view = <DefaultBreakpointsView services="{this._services}" />
      const breakpointsOptions = {
        attachedViews: view
      }
      this._services.requestService('breakpoints',breakpointsOptions)
      const viewOptions = {
        allowDefaultConsole: true,
        allowDefaultDebugger: true,
        uriPrefix:'php-debug',
        debugViewTitle:'PHP Debug',
        consoleViewTitle:'PHP Console',
        combineBreakpointsWatchpoints: false
      }
      this._services.requestService('debugview',viewOptions,this.debugViewServiceActivated.bind(this))
      this._services.getLoggerService().info("Received Debug UI Services")
    } catch (err) {
      atom.notifications.addError(`Failed to load PHP-Debug`, {
        detail: err,
        dismissable: true
      })
      throw err
    }
  }

  getGrammarScopes() {
     return ['text.html.php'];
  }

  consumeDatatip(service) {
    let provider = {
      providerName: "PHPDebugLanguageClient",
      priority: 12,
      grammarScopes: this.getGrammarScopes(),
      validForScope: (scopeName) => {
        return this.getGrammarScopes().includes(scopeName)
      },
      datatip: this.getDatatip.bind(this)
    }
    service.addProvider(provider);
  }

  getDatatip(tipEditor, tipPoint) {
    return new Promise((resolve,reject) => {
      if (this._engine == undefined || this._engine == null) {
        reject();
        return;
      }
      let pkg = atom.packages.getActivePackage("ide-php")
      if (pkg == undefined || pkg == null) {
        reject();
        return;
      }
      pkg.mainModule.getDatatip(tipEditor,tipPoint).then((result) => {
        let editor = atom.workspace.getActivePaneItem();
        if (editor == undefined || editor == null || editor.getTextInBufferRange == undefined || result == undefined || result == null) {
          reject();
          return;
        } else {
          let highlight = editor.getTextInBufferRange(result.range);
          let debugContext = this._engine.tryGetContext();
          if (debugContext == undefined || debugContext == null) {
            reject();
            return;
          }
          if (highlight == undefined || highlight == null) {
            reject();
            return;
          } else {
            let p = debugContext.evalExpression(highlight)
            p.then((data) => {
              let markedString = {
                grammar: editor.getGrammar(),
                type: "snippet",
                value: "\"" + data + "\""
              }
              if (result.markedStrings != undefined && result.markedStrings != null) {
                result.markedStrings = [];
                result.markedStrings.push(markedString);
              }
              resolve(result)
              return;
            });
          }
        }
      }).catch((error) => {
        reject(error);
        return;
      });
    });
  }

  debugViewServiceActivated(service,options) {
    this._subscriptions.add(service.onDefaultDebuggerRequested(() => {
      this._engine.createDebuggingContext("default").then( (context) => {
        const uiService = context.getUIService()
        if (uiService != null) {
          uiService.activateDebugger()
        }
      })
    }))
    this._subscriptions.add(service.onDefaultConsoleRequested(() => {
      this._engine.createDebuggingContext("default").then( (context) => {
        const uiService = context.getUIService()
        if (uiService != null) {
          uiService.activateDebugger()
        }
      })
    }))
    this._subscriptions.add(service.onContextCreated(this.debugContextViewServiceCreated.bind(this)))
  }

  actionsServiceActivated(service,options) {
    service.hideActionButtons(['attach','run'])
  }

  debugContextViewServiceCreated(event) {
    event.service.enablePanels(['watches','breakpoints','context','stack'])
  }

  serviceRegistered(event) {
    this._services.getLoggerService().info('Service registered: ' + event.name)
  }

  consumeStatusBar (statusBar) {
    this._subscriptions.add(atom.config.observe("php-debug.display.enableStatusbarButtons", (enable) => {
      if (enable) {
        this._debugView = new StatusBarDebugView({statusBar:statusBar, engine:this._engine})
        this._consoleView = new StatusBarConsoleView({statusBar:statusBar, engine:this._engine})
      }
      else {
        if (this._consoleView != undefined && this._consoleView != null) {
          this._consoleView.destroy()
          delete this._consoleView
        }
        if (this._debugView != undefined && this._debugView != null) {
          this._debugView.destroy()
          delete this._debugView
        }
      }
    }))
  }

  deactivate() {
    if (this._engine != undefined && this._engine != null) {
      this._engine.destroy()
      delete this._services
    }
    if (this._service != undefined && this._engine != null) {
      this._services.destroy()
      delete this._services
    }
    this._subscriptions.dispose()
    delete this._subscriptions
  }

  serialize() {
    if (this._services != undefined && this._services != null) {
      var results = {
        "deserializer": "PHPDebug",
        "data": {
          "services" : this._services.serialize()
        }
      }
      return results;
    }
    return {};
  }
  deserialize(state) {
    if (state != null) {
      if (typeof state.data === "object") {
        return state.data;
      } else {
        return {"services":null}
      }
    }
  }
}
atom.deserializers.add(PHPDebug);
module.exports = new PHPDebug()
<|endoftext|>


<commit_before>// ==UserScript==
// @name          Pxer-6
// @namespace     https://github.com/pea3nut/Pxer
// @description   pixiv.net Tools
// @include       http://www.pixiv.net/member_illust.php*
// @include       http://www.pixiv.net/bookmark.php*
// @include       http://www.pixiv.net/search.php*
// ==/UserScript==
javascript:void((function() {
    pxerDefinePxerConfig ={
        "URL_ROOT":"http://127.0.0.1/github/pxer-beta-6/",
        "TEMPLATE_URL":'lib/template.php',
        "DEBUG":false,
        "CACHE":true,
    };
    document.head.appendChild(
        document.createElement("script")
    ).src
        =window.pxerDefinePxerConfig['URL_ROOT']+"lib/launcher.js"
        +"?pixiv_id="+document.cookie.match(/PHPSESSID=(\d+)/)[1]
        +"&time="+(new Date()).getTime()
})());
<commit_msg>修正Greasemonkey启动bug<commit_after>// ==UserScript==
// @name          Pxer-6
// @version       6.0.2
// @namespace     https://github.com/pea3nut/Pxer
// @author        花生PeA
// @description   pixiv.net Tools
// @grant         none
// @include       http://www.pixiv.net/member_illust.php*
// @include       http://www.pixiv.net/bookmark.php*
// @include       http://www.pixiv.net/search.php*
// ==/UserScript==
javascript:void((function() {
    function loadPxer(){
        window.pxerDefinePxerConfig ={
            "URL_ROOT":"http://127.0.0.1/github/pxer-beta-6/",
            "TEMPLATE_URL":'lib/template.php',
            "DEBUG":false,
            "CACHE":true,
        };
        document.head.appendChild(
            document.createElement("script")
        ).src
            =window.pxerDefinePxerConfig['URL_ROOT']+"lib/launcher.js"
            +"?pixiv_id="+document.cookie.match(/PHPSESSID=(\d+)/)[1]
            +"&time="+(new Date()).getTime()
        ;
    };
    if(document.readyState !=='loading'){
        setTimeout(loadPxer);
    }else{
        document.addEventListener('DOMContentLoaded' ,loadPxer);
    };
})());
<|endoftext|>


<commit_before>// A reactive version of amplify.store(). This object acts a little like the Session object, but
// the key/value store is persisted on the client using amplify, so it survives page refresh
// and retains its values between sessions.

reamplify = {
  deps: {},
  store: function (key, value) {
    var self = this;
    console.log (this.deps)
    if (value === null) {
      //delete key
      if (self.deps[key])
        delete self.deps[key];
      console.log(self.deps);
      return amplify.store(key, null);
    }
    else if (value) {
      //add/update
      var previousValue = amplify.store(key);
      if (self.deps[key] && value !== previousValue)
        self.deps[key].changed()
      console.log(self.deps);
      return amplify.store(key, value);
    }
    else if (key) {
      // get value of key
      var result;
      result = amplify.store(key);
      if (! self.deps[key])
        self.deps[key] = new Deps.Dependency
      self.deps[key].depend();
      console.log(self.deps);
      return result;
    }
    else {
      //not implemented
      throw new Error ('reAmplify cannot reactively return the entire amplify store. ' +
        'Use amplify.store() instead');
    };
  }
};<commit_msg>fix: run get, not set, when passed `value` is `undefined`<commit_after>// A reactive version of amplify.store(). This object acts a little like the Session object, but
// the key/value store is persisted on the client using amplify, so it survives page refresh
// and retains its values between sessions.

reamplify = {
  deps: {},
  store: function (key, value) {
    var self = this;
    if (value === null) {
      //delete key
      if (self.deps[key])
        delete self.deps[key];
      return amplify.store(key, null);
    }
    else if (value !== undefined) {
      //add/update
      var previousValue = amplify.store(key);
      if (self.deps[key] && value !== previousValue){
        self.deps[key].changed()
      }
      return amplify.store(key, value);
    }
    else if (key) {
      // get value of key
      var result;
      result = amplify.store(key);
      if (! self.deps[key])
        self.deps[key] = new Deps.Dependency
      self.deps[key].depend();
      return result;
    }
    else {
      //not implemented
      throw new Error ('reAmplify cannot reactively return the entire amplify store. ' +
        'Use amplify.store() instead');
    };
  }
};<|endoftext|>


<commit_before>exports.create = function() {

  var _svg = '',
    _tagName, _attributes, _coordinates;

  function _addPathToSvg() {
    if (!_tagName) {
      return;
    }
    if (_attributes.fill === 'none' && _attributes.stroke === 'none') {
      return;
    }
    _svg += '<' + _tagName;
    for (var p in _attributes) {
      _svg += ' ' + p + '="' + _attributes[p] + '"';
    }
    _svg += ' ' + d + '="' + _coordinates.join(' ') + '"';
    _svg += '/>\n';
  }

  var canvas = {
    style: {}
  };

  canvas.getContext = function(contextType) {
    if (contextType === '2d') {
      return context;
    }
  };

  canvas.toDataURL = function(mimeType) {
    if (mimeType === 'image/svg') {
      var res = '';
      res += '<?xml version="1.0" standalone="no"?>\n';
      res += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
      res += '<svg width="' + (canvas.width || 1) + '" height="' + (canvas.width || 1) + '" version="1.1" xmlns="http://www.w3.org/2000/svg">\n';
      res += _svg;
      res += '</svg>';

//    viewBox= [min.x, min.y, width, height].join(' ')

      return res;
    }
  };

  var context = {
//    globalCompositeOperation = 'source-over'
  };

  context.arc = function(x, y, r, start, end, clockwise) {};

  context.clearRect = function() {
    _svg = '';
  };

  context.beginPath = function() {
    _addPathToSvg();

    _tagName + 'path';
    _attributes = { fill:'none', stroke:'none' };
    _coordinates = [];
  };

  context.closePath = function() {
    _coordinates.push('z');
  };

  context.fill = function() {
    delete _attributes.fill;
		context.fillStyle && (_attributes['fill']          = context.fillStyle);
//  context.fillStyle && (_attributes['fill-opacity']  = context.fillStyle);
  };

  context.stroke = function() {
    delete _attributes.stroke;
    context.lineCap     && (_attributes['stroke-linecap']  = context.lineCap);
    context.lineJoin    && (_attributes['stroke-linejoin'] = context.lineJoin);
		context.strokeStyle && (_attributes['stroke']          = context.strokeStyle);
//  context.strokeStyle && (_attributes['stroke-opacity']  = context.strokeStyle);
		context.lineWidth   && (_attributes['stroke-width']    = context.lineWidth);
//  _attributes += ('stroke-dasharray'] = options.dashArray;
  };

  context.lineTo = function(x, y) {
		_path.setAttribute('L', x, y);
  };

  context.moveTo = function(x, y) {
    _coordinates.push('M', x, y);
  };

  context.drawImage = function(img, x, y) {};

  return canvas;
};
<commit_msg>svgvas WIP<commit_after>exports.create = function() {

  var
    ns = 'http://www.w3.org/2000/svg',
    style = {},
    doc = document.createElement('SVG'),
    el,
    coordinates = [];

  doc.setAttributeNS(ns, 'xmlns', 'http://www.w3.org/2000/svg');
  doc.setAttributeNS(ns, 'version', 1.1);

  var canvas = {
    style: {}
  };

  canvas.getContext = function(type) {
    if (type === '2d') {
      return context;
    }
  };

  canvas.toDataURL = function() {
//  res += '<?xml version="1.0" standalone="no"?>\n';
//  res += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
//  viewBox= [min.x, min.y, width, height].join(' ')
    doc.setAttributeNS(ns, 'width', (canvas.width || 1));
    doc.setAttributeNS(ns, 'height', (canvas.height || 1));
    return doc.toString();
  };

  var context = {};

  context.arc = function(x, y, r, start, end, clockwise) {};

  context.clearRect = function() {
    while (doc.removeChild(doc.firstChild));
  };

  context.beginPath = function() {
    doc.appendchild(el = document.createElementNS(ns, 'path'));
    coordinates = [];
  };

  context.closePath = function() {
    coordinates.push('z');
    el.setAttributeNS(ns, 'd', coordinates.join(' '));
  };

  context.moveTo = function(x, y) {
    coordinates.push('M', x, y);
  };

  context.lineTo = function(x, y) {
		coordinates.push('L', x, y);
  };

  context.stroke = function() {
    context.lineCap     && el.setAttributeNS(ns, 'stroke-linecap',  context.lineCap);
    context.lineJoin    && el.setAttributeNS(ns, 'stroke-linejoin', context.lineJoin);
    context.strokeStyle && el.setAttributeNS(ns, 'stroke',          context.strokeStyle);
    context.lineWidth   && el.setAttributeNS(ns, 'stroke-width',    context.lineWidth);
//  context.strokeStyle && (style['stroke-opacity']  = context.strokeStyle);
//  style += ('stroke-dasharray'] = options.dashArray;
  };

  context.fill = function() {
		context.fillStyle && el.setAttributeNS(ns, 'fill', context.fillStyle);
//  context.fillStyle && el.setAttributeNS(ns, 'fill-opacity', context.fillStyle);
  };

  context.drawImage = function(img, x, y) {};

  context.arc = function() {};
  context.bezierCurveTo = function() {};
  context.clearRect = function() {};
  context.getImageData = function() {};
  context.putImageData = function() {};

  context.fillStyle = null;
  context.globalCompositeOperation = null;
  context.lineCap = null;
  context.lineJoin = null;
  context.lineWidth = null;
  context.mozImageSmoothingEnabled = null;
  context.shadowBlur = null;
  context.shadowColor = null;
  context.strokeStyle = null;
  context.webkitImageSmoothingEnabled = null;

  return canvas;
};
<|endoftext|>


<commit_before>var config = require('./config.json'),
  logger = require('./my_modules/logger.js'),
  Web = require('./my_modules/web.js'),
  BaseShowScraper = require('./my_modules/baseShowScraper.js'),
  EpisodeActorGrabber = require('./my_modules/episodeActorGrabber.js'),
  ActorCreditsGrabber = require('./my_modules/actorCreditsGrabber.js');

var svu = 'tt0203259';
var friends = 'tt0108778';

var base = new BaseShowScraper(config, friends);
var cast = new EpisodeActorGrabber(config);
var credits = new ActorCreditsGrabber(config);

base.on('done',function(baseId) {
  logger.log({
    caller: 'BaseShowScraper',
    message: 'done',
    params: baseId
  });
});

//base.start();
//cast.start();
//credits.start();

var web = new Web(config);
web.startServer();<commit_msg>add seinfeld<commit_after>var config = require('./config.json'),
  logger = require('./my_modules/logger.js'),
  Web = require('./my_modules/web.js'),
  BaseShowScraper = require('./my_modules/baseShowScraper.js'),
  EpisodeActorGrabber = require('./my_modules/episodeActorGrabber.js'),
  ActorCreditsGrabber = require('./my_modules/actorCreditsGrabber.js');

var svu = 'tt0203259';
var friends = 'tt0108778';
var seinfeld = 'tt0098904';

var base = new BaseShowScraper(config, seinfeld);
var cast = new EpisodeActorGrabber(config);
var credits = new ActorCreditsGrabber(config);

base.on('done',function(baseId) {
  logger.log({
    caller: 'BaseShowScraper',
    message: 'done',
    params: baseId
  });
});

base.start();
cast.start();
credits.start(false);

var web = new Web(config);
web.startServer();<|endoftext|>


<commit_before>var git = require('../');

var Reference = function(rawReference) {
  var self = {};

  if(rawReference instanceof git.raw.Reference) {
    self.reference = rawReference;
  } else if(rawReference instanceof git.raw.Repo) {
    self.repo = rawReference;
    self.reference = new git.raw.Reference(rawReference);
  }

  self.lookup = function(name, callback) {
    self.reference.lookup(self.repo, name, function(error, reference) {
      if (error) {
        callback(git.error(error), self);
        return;
      }
      self.reference = reference;
      callback(null, self);
    });
  };

  self.oid = function(callback) {
    self.reference.oid(function(error, rawOid) {
      if (error) {
        callback(git.error(error, self));
        return;
      }
      callback(null, git.oid(rawOid));
    });
  };

  return self;
};

exports.reference = Reference;
<commit_msg>Refactored reference.js<commit_after>var git = require('../'),
    success = require('./utilities').success;

/**
 * Convenience reference constructor.
 *
 * @constructor
 * @param {git.raw.Repo} rawRepo
 * @param {git.raw.Reference|null} rawReference
 */
var Reference = function(rawRepo, rawReference) {
  if (!(rawRepo instanceof git.raw.Repo)) {
    throw git.error('First parameter for Reference must be a raw repo');
  }
  this.rawRepo = rawRepo;

  if (rawReference instanceof git.raw.Reference) {
    this.rawReference = rawReference;
  } else {
    this.rawReference = new git.raw.Reference(this.rawRepo);
  }
};

/**
 * Lookup the reference with the given name.
 *
 * @param  {String}   name
 * @param  {Function} callback
 */
Reference.prototype.lookup = function(name, callback) {
  var self = this;
  self.rawReference.lookup(self.rawRepo, name, function referenceLookup(error, rawReference) {
    if (!success(error, callback)) {
      return;
    }
    self.rawReference = rawReference;
    callback(null, self);
  });
};

/**
 * Get the Oid representing this reference.
 *
 * @param  {Function} callback
 */
Reference.prototype.oid = function(callback) {
  this.rawReference.oid(function referenceOid(error, rawOid) {
    if (success(error, callback)) {
      callback(null, new git.oid(rawOid));
    }
  });
};

exports.reference = Reference;
<|endoftext|>


<commit_before><commit_msg>Updated Mesh.js<commit_after>EZ3.Mesh = function(data) {
  EZ3.Entity.call(this);

  this._buffer = new EZ3.Buffer();
  this.dynamic = data.dynamic || false;
  this.material = data.material || null;
  this.geometry = (data.geometry instanceof EZ3.Geometry) ? data.geometry : null;
};

EZ3.Mesh.prototype = Object.create(EZ3.Entity.prototype);
EZ3.Mesh.prototype.constructor = EZ3.Mesh;

EZ3.Mesh.prototype.init = function(gl) {
  var hint = (this.dynamic) ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;

  if(this.geometry.verticesNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.VERTEX, this.geometry.vertices.length, this.geometry.vertices, hint);
    this.geometry.verticesNeedUpdate = false;
  }

  if(this.geometry.normalsNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.NORMAL, this.geometry.normals.length, this.geometry.normals, hint);
    this.geometry.normalsNeedUpdate = false;
  }

  if(this.geometry.uvNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.UV, this.geometry.uv.length, this.geometry.uv, hint);
    this.geometry.uvNeedUpdate = false;
  }

  if(this.geometry.tangentsNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.TANGENTS, this.geometry.tangents.length, this.geometry.tangents, hint);
    this.geometry.tangentNeedUpdate = false;
  }

  if(this.geometry.bitangentsNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.BITANGENTS, this.geometry.bitangents.length, this.geometry.bitangents, hint);
    this.geometry.bitangentsNeedUpdate = false;
  }

  if(this.geometry.indicesNeedUpdate){
    this._buffer.init(gl, EZ3.Buffer.INDEX, this.geometry.indices.length, this.geometry.indices, hint);
    this.geometry.indicesNeedUpdate = false;
  }
};

EZ3.Mesh.prototype.draw = function(gl) {
  if(this.geometry.indices.length){
    this._buffer.draw(gl, EZ3.ELEMENTS_DRAW, this.geometry.indices.length);
  }else{
    this._buffer.draw(gl, EZ3.ARRAYS_DRAW, this.geometry.vertices.length);
  }
};
<|endoftext|>


<commit_before>/*!
 * Dependencies
 */
var i8n = require('inflection');
var defineScope = require('./scope.js').defineScope;
var ModelBaseClass = require('./model.js');

module.exports = Relation;

/**
 * Relations class
 *
 * @class Relation
 */
function Relation() {
}

/**
 * Find the relation by foreign key
 * @param {*} foreignKey The foreign key
 * @returns {Object} The relation object
 */
Relation.relationNameFor = function relationNameFor(foreignKey) {
  for (var rel in this.relations) {
    if (this.relations[rel].type === 'belongsTo' && this.relations[rel].keyFrom === foreignKey) {
      return rel;
    }
  }
};

/*!
 * Look up a model by name from the list of given models
 * @param {Object} models Models keyed by name
 * @param {String} modelName The model name
 * @returns {*} The matching model class
 */
function lookupModel(models, modelName) {
  if(models[modelName]) {
    return models[modelName];
  }
  var lookupClassName = modelName.toLowerCase();
  for (var name in models) {
    if (name.toLowerCase() === lookupClassName) {
      return models[name];
    }
  }
}

/**
 * Declare "hasMany" relation.
 * Example:
 * ```User.hasMany(Post, {as: 'posts', foreignKey: 'authorId'});```
 *
 * @param {Relation} anotherClass Class to has many
 * @param {Object} params Configuration {as:, foreignKey:}
 */
Relation.hasMany = function hasMany(anotherClass, params) {
  var thisClassName = this.modelName;
  params = params || {};
  if (typeof anotherClass === 'string') {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      var anotherClassName = i8n.singularize(anotherClass).toLowerCase();
      anotherClass = lookupModel(this.dataSource.modelBuilder.models, anotherClassName);
    }
  }
  var methodName = params.as || i8n.camelize(anotherClass.pluralModelName, true);
  var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true);

  var idName = this.dataSource.idName(this.modelName) || 'id';

  this.relations[methodName] = {
    type: 'hasMany',
    keyFrom: idName,
    keyTo: fk,
    modelTo: anotherClass,
    multiple: true
  };

  if (params.through) {
    this.relations[methodName].modelThrough = params.through;
  }
  // each instance of this class should have method named
  // pluralize(anotherClass.modelName)
  // which is actually just anotherClass.find({where: {thisModelNameId: this[idName]}}, cb);
  var scopeMethods = {
    findById: findById,
    destroy: destroyById
  };
  if (params.through) {
    var fk2 = i8n.camelize(anotherClass.modelName + '_id', true);

    // Create an instance of the target model and connect it to the instance of
    // the source model by creating an instance of the through model
    scopeMethods.create = function create(data, done) {
      if (typeof data !== 'object') {
        done = data;
        data = {};
      }
      if ('function' !== typeof done) {
        done = function () {
        };
      }
      var self = this;
      // First create the target model
      anotherClass.create(data, function (err, ac) {
        if (err) return done(err, ac);
        var d = {};
        d[params.through.relationNameFor(fk)] = self;
        d[params.through.relationNameFor(fk2)] = ac;
        // Then create the through model
        params.through.create(d, function (e) {
          if (e) {
            // Undo creation of the target model
            ac.destroy(function () {
              done(e);
            });
          } else {
            done(err, ac);
          }
        });
      });
    };

    /**
     * Add the target model instance to the 'hasMany' relation
     * @param {Object|ID) acInst The actual instance or id value
     */
    scopeMethods.add = function (acInst, done) {
      var data = {};
      var query = {};
      query[fk] = this[idName];
      data[params.through.relationNameFor(fk)] = this;
      query[fk2] = acInst[idName] || acInst;
      data[params.through.relationNameFor(fk2)] = acInst;
      // Create an instance of the through model
      params.through.findOrCreate({where: query}, data, done);
    };

    /**
     * Remove the target model instance from the 'hasMany' relation
     * @param {Object|ID) acInst The actual instance or id value
     */
    scopeMethods.remove = function (acInst, done) {
      var q = {};
      q[fk2] = acInst[idName] || acInst;
      params.through.findOne({where: q}, function (err, d) {
        if (err) {
          return done(err);
        }
        if (!d) {
          return done();
        }
        d.destroy(done);
      });
    };

    // No destroy method will be injected
    delete scopeMethods.destroy;
  }

  // Mix the property and scoped methods into the prototype class
  defineScope(this.prototype, params.through || anotherClass, methodName, function () {
    var filter = {};
    filter.where = {};
    filter.where[fk] = this[idName];
    if (params.through) {
      filter.collect = i8n.camelize(anotherClass.modelName, true);
      filter.include = filter.collect;
    }
    return filter;
  }, scopeMethods);

  if (!params.through) {
    // obviously, anotherClass should have attribute called `fk`
    anotherClass.dataSource.defineForeignKey(anotherClass.modelName, fk, this.modelName);
  }

  // Find the target model instance by id
  function findById(id, cb) {
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(new Error('Not found'));
      }
      // Check if the foreign key matches the primary key
      if (inst[fk] && inst[fk].toString() === this[idName].toString()) {
        cb(null, inst);
      } else {
        cb(new Error('Permission denied'));
      }
    }.bind(this));
  }

  // Destroy the target model instance by id
  function destroyById(id, cb) {
    var self = this;
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(new Error('Not found'));
      }
      // Check if the foreign key matches the primary key
      if (inst[fk] && inst[fk].toString() === self[idName].toString()) {
        inst.destroy(cb);
      } else {
        cb(new Error('Permission denied'));
      }
    });
  }

};

/**
 * Declare "belongsTo" relation.
 *
 * **Examples**
 *
 * Suppose the model Post has a *belongsTo* relationship with User (the author of the post). You could declare it this way:
 * ```js
 * Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
 * ```
 *
 * When a post is loaded, you can load the related author with:
 * ```js
 * post.author(function(err, user) {
 *     // the user variable is your user object
 * });
 * ```
 *
 * The related object is cached, so if later you try to get again the author, no additional request will be made.
 * But there is an optional boolean parameter in first position that set whether or not you want to reload the cache:
 * ```js
 * post.author(true, function(err, user) {
 *     // The user is reloaded, even if it was already cached.
 * });
 * ```
 * This optional parameter default value is false, so the related object will be loaded from cache if available.
 *
 * @param {Class} anotherClass Class to belong
 * @param {Object} params Configuration {as: 'propertyName', foreignKey: 'keyName'}
 *
 */
Relation.belongsTo = function (anotherClass, params) {
  params = params || {};
  if ('string' === typeof anotherClass) {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      var anotherClassName = anotherClass.toLowerCase();
      anotherClass = lookupModel(this.dataSource.modelBuilder.models, anotherClassName);
    }
  }

  var idName = this.dataSource.idName(anotherClass.modelName) || 'id';
  var methodName = params.as || i8n.camelize(anotherClass.modelName, true);
  var fk = params.foreignKey || methodName + 'Id';

  this.relations[methodName] = {
    type: 'belongsTo',
    keyFrom: fk,
    keyTo: idName,
    modelTo: anotherClass,
    multiple: false
  };

  this.dataSource.defineForeignKey(this.modelName, fk, anotherClass.modelName);
  this.prototype.__finders__ = this.prototype.__finders__ || {};

  // Set up a finder to find by id and make sure the foreign key of the declaring
  // model matches the primary key of the target model
  this.prototype.__finders__[methodName] = function (id, cb) {
    if (id === null) {
      cb(null, null);
      return;
    }
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(null, null);
      }
      // Check if the foreign key matches the primary key
      if (inst[idName] === this[fk]) {
        cb(null, inst);
      } else {
        cb(new Error('Permission denied'));
      }
    }.bind(this));
  };

  // Define the method for the belongsTo relation itself
  // It will support one of the following styles:
  // - order.customer(refresh, callback): Load the target model instance asynchronously
  // - order.customer(customer): Synchronous setter of the target model instance
  // - order.customer(): Synchronous getter of the target model instance
  var relationMethod = function (refresh, p) {
    if (arguments.length === 1) {
      p = refresh;
      refresh = false;
    } else if (arguments.length > 2) {
      throw new Error('Method can\'t be called with more than two arguments');
    }
    var self = this;
    var cachedValue;
    if (!refresh && this.__cachedRelations && (this.__cachedRelations[methodName] !== undefined)) {
      cachedValue = this.__cachedRelations[methodName];
    }
    if (p instanceof ModelBaseClass) { // acts as setter
      this[fk] = p[idName];
      this.__cachedRelations[methodName] = p;
    } else if (typeof p === 'function') { // acts as async getter
      if (typeof cachedValue === 'undefined') {
        this.__finders__[methodName].apply(self, [this[fk], function (err, inst) {
          if (!err) {
            self.__cachedRelations[methodName] = inst;
          }
          p(err, inst);
        }]);
        return this[fk];
      } else {
        p(null, cachedValue);
        return cachedValue;
      }
    } else if (typeof p === 'undefined') { // acts as sync getter
      return this[fk];
    } else { // setter
      this[fk] = p;
      delete this.__cachedRelations[methodName];
    }
  };

  // Define a property for the scope so that we have 'this' for the scoped methods
  Object.defineProperty(this.prototype, methodName, {
    enumerable: true,
    configurable: true,
    get: function () {
      var fn = function() {
        // Call the relation method on the declaring model instance
        return relationMethod.apply(this, arguments);
      }
      // Create an instance of the target model and set the foreign key of the
      // declaring model instance to the id of the target instance
      fn.create = function(targetModelData, cb) {
        var self = this;
        anotherClass.create(targetModelData, function(err, targetModel) {
          if(!err) {
            self[fk] = targetModel[idName];
            cb && cb(err, targetModel);
          } else {
            cb && cb(err);
          }
        });
      }.bind(this);

      // Build an instance of the target model
      fn.build = function(targetModelData) {
        return new anotherClass(targetModelData);
      }.bind(this);

      fn._targetClass = anotherClass.modelName;

      return fn;
    }});

  // Wrap the property into a function for remoting
  // so that it can be accessed as /api/<model>/<id>/<belongsToRelationName>
  // For example, /api/orders/1/customer
  var fn = function() {
    var f = this[methodName];
    f.apply(this, arguments);
  };

  fn.shared = true;
  fn.http = {verb: 'get', path: '/' + methodName};
  fn.accepts = {arg: 'refresh', type: 'boolean', http: {source: 'query'}};
  fn.description = 'Fetches belongsTo relation ' + methodName;
  fn.returns = {arg: methodName, type: 'object', root: true};

  this.prototype['__get__' + methodName] = fn;
};

/**
 * Many-to-many relation
 *
 * For example, this creates connection model 'PostTag':
 * ```js
 * Post.hasAndBelongsToMany('tags');
 * ```
 * @param {String|Function} anotherClass - target class to hasAndBelongsToMany or name of
 * the relation
 * @param {Object} params - configuration {as: String, foreignKey: *, model: ModelClass}
 */
Relation.hasAndBelongsToMany = function hasAndBelongsToMany(anotherClass, params) {
  params = params || {};
  var models = this.dataSource.modelBuilder.models;

  if ('string' === typeof anotherClass) {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      anotherClass = lookupModel(models, i8n.singularize(anotherClass).toLowerCase()) ||
        anotherClass;
    }
    if (typeof anotherClass === 'string') {
      throw new Error('Could not find "' + anotherClass + '" relation for ' + this.modelName);
    }
  }

  if (!params.through) {
    var name1 = this.modelName + anotherClass.modelName;
    var name2 = anotherClass.modelName + this.modelName;
    params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
      this.dataSource.define(name1);
  }
  params.through.belongsTo(this);
  params.through.belongsTo(anotherClass);

  this.hasMany(anotherClass, {as: params.as, through: params.through});

};
<commit_msg>Updated JSDoc comments with content from .md file<commit_after>/*!
 * Dependencies
 */
var i8n = require('inflection');
var defineScope = require('./scope.js').defineScope;
var ModelBaseClass = require('./model.js');

module.exports = Relation;

/**
 * Relations class.  Use to define relationships between models.
 *
 * @class Relation
 */
function Relation() {
}

/**
 * Find the relation by foreign key
 * @param {*} foreignKey The foreign key
 * @returns {Object} The relation object
 */
Relation.relationNameFor = function relationNameFor(foreignKey) {
  for (var rel in this.relations) {
    if (this.relations[rel].type === 'belongsTo' && this.relations[rel].keyFrom === foreignKey) {
      return rel;
    }
  }
};

/*!
 * Look up a model by name from the list of given models
 * @param {Object} models Models keyed by name
 * @param {String} modelName The model name
 * @returns {*} The matching model class
 */
function lookupModel(models, modelName) {
  if(models[modelName]) {
    return models[modelName];
  }
  var lookupClassName = modelName.toLowerCase();
  for (var name in models) {
    if (name.toLowerCase() === lookupClassName) {
      return models[name];
    }
  }
}

/**
 * Define a "one to many" relationship by specifying the model name
 *
 * Examples:
 * ```
 * User.hasMany(Post, {as: 'posts', foreignKey: 'authorId'});
 * ```
 *
 * ```
 * Book.hasMany(Chapter);
 * ```
 * Or, equivalently:
 * ```
 * Book.hasMany('chapters', {model: Chapter});
 * ```
 * @param {Relation} anotherClass Class to has many
 * @options {Object} parameters Configuration parameters
 * @property {String} as
 * @property {String} foreignKey Property name of foreign key field.
 * @property {Object} model Model object
 */
Relation.hasMany = function hasMany(anotherClass, params) {
  var thisClassName = this.modelName;
  params = params || {};
  if (typeof anotherClass === 'string') {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      var anotherClassName = i8n.singularize(anotherClass).toLowerCase();
      anotherClass = lookupModel(this.dataSource.modelBuilder.models, anotherClassName);
    }
  }
  var methodName = params.as || i8n.camelize(anotherClass.pluralModelName, true);
  var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true);

  var idName = this.dataSource.idName(this.modelName) || 'id';

  this.relations[methodName] = {
    type: 'hasMany',
    keyFrom: idName,
    keyTo: fk,
    modelTo: anotherClass,
    multiple: true
  };

  if (params.through) {
    this.relations[methodName].modelThrough = params.through;
  }
  // each instance of this class should have method named
  // pluralize(anotherClass.modelName)
  // which is actually just anotherClass.find({where: {thisModelNameId: this[idName]}}, cb);
  var scopeMethods = {
    findById: findById,
    destroy: destroyById
  };
  if (params.through) {
    var fk2 = i8n.camelize(anotherClass.modelName + '_id', true);

    // Create an instance of the target model and connect it to the instance of
    // the source model by creating an instance of the through model
    scopeMethods.create = function create(data, done) {
      if (typeof data !== 'object') {
        done = data;
        data = {};
      }
      if ('function' !== typeof done) {
        done = function () {
        };
      }
      var self = this;
      // First create the target model
      anotherClass.create(data, function (err, ac) {
        if (err) return done(err, ac);
        var d = {};
        d[params.through.relationNameFor(fk)] = self;
        d[params.through.relationNameFor(fk2)] = ac;
        // Then create the through model
        params.through.create(d, function (e) {
          if (e) {
            // Undo creation of the target model
            ac.destroy(function () {
              done(e);
            });
          } else {
            done(err, ac);
          }
        });
      });
    };

    /**
     * Add the target model instance to the 'hasMany' relation
     * @param {Object|ID) acInst The actual instance or id value
     */
    scopeMethods.add = function (acInst, done) {
      var data = {};
      var query = {};
      query[fk] = this[idName];
      data[params.through.relationNameFor(fk)] = this;
      query[fk2] = acInst[idName] || acInst;
      data[params.through.relationNameFor(fk2)] = acInst;
      // Create an instance of the through model
      params.through.findOrCreate({where: query}, data, done);
    };

    /**
     * Remove the target model instance from the 'hasMany' relation
     * @param {Object|ID) acInst The actual instance or id value
     */
    scopeMethods.remove = function (acInst, done) {
      var q = {};
      q[fk2] = acInst[idName] || acInst;
      params.through.findOne({where: q}, function (err, d) {
        if (err) {
          return done(err);
        }
        if (!d) {
          return done();
        }
        d.destroy(done);
      });
    };

    // No destroy method will be injected
    delete scopeMethods.destroy;
  }

  // Mix the property and scoped methods into the prototype class
  defineScope(this.prototype, params.through || anotherClass, methodName, function () {
    var filter = {};
    filter.where = {};
    filter.where[fk] = this[idName];
    if (params.through) {
      filter.collect = i8n.camelize(anotherClass.modelName, true);
      filter.include = filter.collect;
    }
    return filter;
  }, scopeMethods);

  if (!params.through) {
    // obviously, anotherClass should have attribute called `fk`
    anotherClass.dataSource.defineForeignKey(anotherClass.modelName, fk, this.modelName);
  }

  // Find the target model instance by id
  function findById(id, cb) {
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(new Error('Not found'));
      }
      // Check if the foreign key matches the primary key
      if (inst[fk] && inst[fk].toString() === this[idName].toString()) {
        cb(null, inst);
      } else {
        cb(new Error('Permission denied'));
      }
    }.bind(this));
  }

  // Destroy the target model instance by id
  function destroyById(id, cb) {
    var self = this;
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(new Error('Not found'));
      }
      // Check if the foreign key matches the primary key
      if (inst[fk] && inst[fk].toString() === self[idName].toString()) {
        inst.destroy(cb);
      } else {
        cb(new Error('Permission denied'));
      }
    });
  }

};

/**
 * Declare "belongsTo" relation that sets up a one-to-one connection with another model, such that each
 * instance of the declaring model "belongs to" one instance of the other model.
 *
 * For example, if an application includes users and posts, and each post can be written by exactly one user.
 * The following code specifies that `Post` has a reference called `author` to the `User` model via the `userId` property of `Post`
 * as the foreign key.
 * ```
 * Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
 * ```
 * You can then access the author in one of the following styles.
 * Get the User object for the post author asynchronously:
 * ```
 * post.author(callback);
 * ```
 * Get the User object for the post author synchronously:
 * ```
 * post.author();
 * Set the author to be the given user:
 * ```
 * post.author(user)
 * ```
 * Examples:
 *
 * Suppose the model Post has a *belongsTo* relationship with User (the author of the post). You could declare it this way:
 * ```js
 * Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
 * ```
 *
 * When a post is loaded, you can load the related author with:
 * ```js
 * post.author(function(err, user) {
 *     // the user variable is your user object
 * });
 * ```
 *
 * The related object is cached, so if later you try to get again the author, no additional request will be made.
 * But there is an optional boolean parameter in first position that set whether or not you want to reload the cache:
 * ```js
 * post.author(true, function(err, user) {
 *     // The user is reloaded, even if it was already cached.
 * });
 * ```
 * This optional parameter default value is false, so the related object will be loaded from cache if available.
 *
 * @param {Class} anotherClass Class to belong
 * @param {Object} Parameters Configuration parameters
 * @property {String} as Can be 'propertyName'
 * @property {String} foreignKey Name of foreign key property.
 *
 */
Relation.belongsTo = function (anotherClass, params) {
  params = params || {};
  if ('string' === typeof anotherClass) {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      var anotherClassName = anotherClass.toLowerCase();
      anotherClass = lookupModel(this.dataSource.modelBuilder.models, anotherClassName);
    }
  }

  var idName = this.dataSource.idName(anotherClass.modelName) || 'id';
  var methodName = params.as || i8n.camelize(anotherClass.modelName, true);
  var fk = params.foreignKey || methodName + 'Id';

  this.relations[methodName] = {
    type: 'belongsTo',
    keyFrom: fk,
    keyTo: idName,
    modelTo: anotherClass,
    multiple: false
  };

  this.dataSource.defineForeignKey(this.modelName, fk, anotherClass.modelName);
  this.prototype.__finders__ = this.prototype.__finders__ || {};

  // Set up a finder to find by id and make sure the foreign key of the declaring
  // model matches the primary key of the target model
  this.prototype.__finders__[methodName] = function (id, cb) {
    if (id === null) {
      cb(null, null);
      return;
    }
    anotherClass.findById(id, function (err, inst) {
      if (err) {
        return cb(err);
      }
      if (!inst) {
        return cb(null, null);
      }
      // Check if the foreign key matches the primary key
      if (inst[idName] === this[fk]) {
        cb(null, inst);
      } else {
        cb(new Error('Permission denied'));
      }
    }.bind(this));
  };

  // Define the method for the belongsTo relation itself
  // It will support one of the following styles:
  // - order.customer(refresh, callback): Load the target model instance asynchronously
  // - order.customer(customer): Synchronous setter of the target model instance
  // - order.customer(): Synchronous getter of the target model instance
  var relationMethod = function (refresh, p) {
    if (arguments.length === 1) {
      p = refresh;
      refresh = false;
    } else if (arguments.length > 2) {
      throw new Error('Method can\'t be called with more than two arguments');
    }
    var self = this;
    var cachedValue;
    if (!refresh && this.__cachedRelations && (this.__cachedRelations[methodName] !== undefined)) {
      cachedValue = this.__cachedRelations[methodName];
    }
    if (p instanceof ModelBaseClass) { // acts as setter
      this[fk] = p[idName];
      this.__cachedRelations[methodName] = p;
    } else if (typeof p === 'function') { // acts as async getter
      if (typeof cachedValue === 'undefined') {
        this.__finders__[methodName].apply(self, [this[fk], function (err, inst) {
          if (!err) {
            self.__cachedRelations[methodName] = inst;
          }
          p(err, inst);
        }]);
        return this[fk];
      } else {
        p(null, cachedValue);
        return cachedValue;
      }
    } else if (typeof p === 'undefined') { // acts as sync getter
      return this[fk];
    } else { // setter
      this[fk] = p;
      delete this.__cachedRelations[methodName];
    }
  };

  // Define a property for the scope so that we have 'this' for the scoped methods
  Object.defineProperty(this.prototype, methodName, {
    enumerable: true,
    configurable: true,
    get: function () {
      var fn = function() {
        // Call the relation method on the declaring model instance
        return relationMethod.apply(this, arguments);
      }
      // Create an instance of the target model and set the foreign key of the
      // declaring model instance to the id of the target instance
      fn.create = function(targetModelData, cb) {
        var self = this;
        anotherClass.create(targetModelData, function(err, targetModel) {
          if(!err) {
            self[fk] = targetModel[idName];
            cb && cb(err, targetModel);
          } else {
            cb && cb(err);
          }
        });
      }.bind(this);

      // Build an instance of the target model
      fn.build = function(targetModelData) {
        return new anotherClass(targetModelData);
      }.bind(this);

      fn._targetClass = anotherClass.modelName;

      return fn;
    }});

  // Wrap the property into a function for remoting
  // so that it can be accessed as /api/<model>/<id>/<belongsToRelationName>
  // For example, /api/orders/1/customer
  var fn = function() {
    var f = this[methodName];
    f.apply(this, arguments);
  };

  fn.shared = true;
  fn.http = {verb: 'get', path: '/' + methodName};
  fn.accepts = {arg: 'refresh', type: 'boolean', http: {source: 'query'}};
  fn.description = 'Fetches belongsTo relation ' + methodName;
  fn.returns = {arg: methodName, type: 'object', root: true};

  this.prototype['__get__' + methodName] = fn;
};

/**
 * A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model.
 * For example, if your application includes users and groups, with each group having many users and each user appearing
 * in many groups, you could declare the models this way:
 * ```
 *  User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'});
 * ```
 *  Then, to get the groups to which the user belongs:
 * ```
 *  user.groups(callback);
 * ```
 *  Create a new group and connect it with the user:
 * ```
 *  user.groups.create(data, callback);
 * ```
 *  Connect an existing group with the user:
 * ```
 *  user.groups.add(group, callback);
 * ```
 *  Remove the user from the group:
 * ```
 *  user.groups.remove(group, callback);
 * ```
 *
 * @param {String|Function} anotherClass - target class to hasAndBelongsToMany or name of
 * the relation
 * @options {Object} params - configuration {as: String, foreignKey: *, model: ModelClass}
 * @property {Object} model Model name
 * @property {String} foreignKey Property name of foreign key field.
 */
Relation.hasAndBelongsToMany = function hasAndBelongsToMany(anotherClass, params) {
  params = params || {};
  var models = this.dataSource.modelBuilder.models;

  if ('string' === typeof anotherClass) {
    params.as = anotherClass;
    if (params.model) {
      anotherClass = params.model;
    } else {
      anotherClass = lookupModel(models, i8n.singularize(anotherClass).toLowerCase()) ||
        anotherClass;
    }
    if (typeof anotherClass === 'string') {
      throw new Error('Could not find "' + anotherClass + '" relation for ' + this.modelName);
    }
  }

  if (!params.through) {
    var name1 = this.modelName + anotherClass.modelName;
    var name2 = anotherClass.modelName + this.modelName;
    params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
      this.dataSource.define(name1);
  }
  params.through.belongsTo(this);
  params.through.belongsTo(anotherClass);

  this.hasMany(anotherClass, {as: params.as, through: params.through});

};
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file or at
 * https://github.com/firebase/superstatic/blob/master/LICENSE
 */
'use strict';

var RSVP = require('rsvp');
var _ = require('lodash');
var mime = require('mime-types');
var path = require('path');
var awaitFinished = RSVP.denodeify(require('on-finished'));
var destroy = require('destroy');

// shink-ray is a fork of compression which supports advanced compression encodings but not ES5.
var compressor;
try {
  compressor = require('shrink-ray')();
} catch(e) {
  console.log('Warning: advanced compression encodings unavailable without ES6/C++11. Falling back to gzip.');
  compressor = require('compression')();
}

var Responder = function(req, res, options) {
  this.req = req;
  this.res = res;
  this.provider = options.provider;
  this.config = options.config || {};
  this.rewriters = options.rewriters || {};
  this.compression = options.compression;
};

Responder.prototype.isNotModified = function(stats) {
  if (stats.etag && stats.etag === this.req.headers['if-none-match']) {
    return true;
  }

  var reqModified = this.req.headers['if-modified-since'];
  if (reqModified) {
    reqModified = new Date(reqModified).getTime();
  }
  if (stats.modified && reqModified && stats.modified < reqModified) {
    return true;
  }

  return false;
};

Responder.prototype.handle = function(item, next) {
  var self = this;
  return this._handle(item).then(function(responded) {
    if (!responded && next) {
      next();
    }
    return responded;
  }).catch(function(err) {
    return self.handleError(err);
  });
};

Responder.prototype._handle = function(item) {
  if (_.isArray(item)) {
    return this.handleStack(item);
  } else if (_.isString(item)) {
    return this.handleFile({file: item});
  } else if (_.isPlainObject(item)) {
    if (item.file) {
      return this.handleFile(item);
    } else if (item.redirect) {
      return this.handleRedirect(item);
    } else if (item.rewrite) {
      return this.handleRewrite(item);
    } else if (item.data) {
      return this.handleData(item);
    }
  } else if (_.isFunction(item)) {
    return this.handleMiddleware(item);
  }

  return RSVP.reject(new Error(JSON.stringify(item) + ' is not a recognized responder directive'));
};

Responder.prototype.handleError = function(err) {
  this.res.statusCode = 500;
  console.log(err.stack);
  this.res.end('Unexpected error occurred.');
};

Responder.prototype.handleStack = function(stack) {
  var self = this;
  if (stack.length) {
    return this._handle(stack.shift()).then(function(responded) {
      return responded ? true : self.handleStack(stack);
    });
  }

  return RSVP.resolve(false);
};

Responder.prototype.handleFile = function(file) {
  var self = this;
  return this.provider(this.req, file.file).then(function(result) {
    if (!result) {
      return false;
    }

    if (self.isNotModified(result)) {
      return self.handleNotModified(result);
    }

    return self.handleFileStream(file, result);
  });
};

Responder.prototype.handleFileStream = function(file, result) {
  var self = this;

  this.streamedFile = file;
  this.res.statusCode = file.status || 200;
  if (this.res.statusCode === 200 && file.file === this.config.errorPage) {
    this.res.statusCode = 404;
  }
  this.res.setHeader('Content-Type', result.contentType || mime.contentType(path.extname(file.file)));
  if (result.size) { this.res.setHeader('Content-Length', result.size); }
  if (result.etag) { this.res.setHeader('ETag', result.etag); }
  if (result.modified) {
    this.res.setHeader('Last-Modified', new Date(result.modified).toUTCString());
  }

  if (this.compression) {
    compressor(this.req, this.res, function() {
      result.stream.pipe(self.res);
    });
  } else {
    result.stream.pipe(self.res);
  }

  return awaitFinished(this.res).then(function() {
    destroy(result.stream);
    return true;
  });
};

Responder.prototype.handleNotModified = function() {
  this.res.statusCode = 304;
  this.res.removeHeader('Content-Type');
  this.res.removeHeader('Content-Length');
  this.res.removeHeader('Transfer-Encoding');
  this.res.end();
};

Responder.prototype.handleRedirect = function(redirect) {
  this.res.statusCode = redirect.status || 301;
  this.res.setHeader('Location', redirect.redirect);
  this.res.setHeader('Content-Type', 'text/html; charset=utf-8');
  this.res.end('Redirecting to ' + redirect.redirect);
  return RSVP.resolve(true);
};

Responder.prototype.handleMiddleware = function(middleware) {
  var self = this;
  return new RSVP.Promise(function(resolve) {
    middleware(self.req, self.res, function() { resolve(false); });
  });
};

Responder.prototype.handleRewrite = function(item) {
  var self = this;
  if (item.rewrite.destination) {
    return self.handleFile({file: item.rewrite.destination});
  }

  for (var key in this.rewriters) {
    if (item.rewrite[key]) {
      return this.rewriters[key](item.rewrite, this).then(function(result) {
        return self._handle(result);
      });
    }
  }
  return RSVP.reject(new Error('Unable to find a matching rewriter for ' + JSON.stringify(item.rewrite)));
};

Responder.prototype.handleData = function(data) {
  this.res.statusCode = data.status || 200;
  this.res.setHeader('Content-Type', data.contentType || 'text/html; charset=utf-8');
  this.res.end(data.data);
  return RSVP.resolve(true);
};

module.exports = Responder;
<commit_msg>fix lint error<commit_after>/**
 * Copyright 2015 Google Inc. All Rights Reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file or at
 * https://github.com/firebase/superstatic/blob/master/LICENSE
 */
'use strict';

var RSVP = require('rsvp');
var _ = require('lodash');
var mime = require('mime-types');
var path = require('path');
var awaitFinished = RSVP.denodeify(require('on-finished'));
var destroy = require('destroy');

// shink-ray is a fork of compression which supports advanced compression encodings but not ES5.
var compressor;
try {
  compressor = require('shrink-ray')();
} catch (e) {
  console.log('Warning: advanced compression encodings unavailable without ES6/C++11. Falling back to gzip.');
  compressor = require('compression')();
}

var Responder = function(req, res, options) {
  this.req = req;
  this.res = res;
  this.provider = options.provider;
  this.config = options.config || {};
  this.rewriters = options.rewriters || {};
  this.compression = options.compression;
};

Responder.prototype.isNotModified = function(stats) {
  if (stats.etag && stats.etag === this.req.headers['if-none-match']) {
    return true;
  }

  var reqModified = this.req.headers['if-modified-since'];
  if (reqModified) {
    reqModified = new Date(reqModified).getTime();
  }
  if (stats.modified && reqModified && stats.modified < reqModified) {
    return true;
  }

  return false;
};

Responder.prototype.handle = function(item, next) {
  var self = this;
  return this._handle(item).then(function(responded) {
    if (!responded && next) {
      next();
    }
    return responded;
  }).catch(function(err) {
    return self.handleError(err);
  });
};

Responder.prototype._handle = function(item) {
  if (_.isArray(item)) {
    return this.handleStack(item);
  } else if (_.isString(item)) {
    return this.handleFile({file: item});
  } else if (_.isPlainObject(item)) {
    if (item.file) {
      return this.handleFile(item);
    } else if (item.redirect) {
      return this.handleRedirect(item);
    } else if (item.rewrite) {
      return this.handleRewrite(item);
    } else if (item.data) {
      return this.handleData(item);
    }
  } else if (_.isFunction(item)) {
    return this.handleMiddleware(item);
  }

  return RSVP.reject(new Error(JSON.stringify(item) + ' is not a recognized responder directive'));
};

Responder.prototype.handleError = function(err) {
  this.res.statusCode = 500;
  console.log(err.stack);
  this.res.end('Unexpected error occurred.');
};

Responder.prototype.handleStack = function(stack) {
  var self = this;
  if (stack.length) {
    return this._handle(stack.shift()).then(function(responded) {
      return responded ? true : self.handleStack(stack);
    });
  }

  return RSVP.resolve(false);
};

Responder.prototype.handleFile = function(file) {
  var self = this;
  return this.provider(this.req, file.file).then(function(result) {
    if (!result) {
      return false;
    }

    if (self.isNotModified(result)) {
      return self.handleNotModified(result);
    }

    return self.handleFileStream(file, result);
  });
};

Responder.prototype.handleFileStream = function(file, result) {
  var self = this;

  this.streamedFile = file;
  this.res.statusCode = file.status || 200;
  if (this.res.statusCode === 200 && file.file === this.config.errorPage) {
    this.res.statusCode = 404;
  }
  this.res.setHeader('Content-Type', result.contentType || mime.contentType(path.extname(file.file)));
  if (result.size) { this.res.setHeader('Content-Length', result.size); }
  if (result.etag) { this.res.setHeader('ETag', result.etag); }
  if (result.modified) {
    this.res.setHeader('Last-Modified', new Date(result.modified).toUTCString());
  }

  if (this.compression) {
    compressor(this.req, this.res, function() {
      result.stream.pipe(self.res);
    });
  } else {
    result.stream.pipe(self.res);
  }

  return awaitFinished(this.res).then(function() {
    destroy(result.stream);
    return true;
  });
};

Responder.prototype.handleNotModified = function() {
  this.res.statusCode = 304;
  this.res.removeHeader('Content-Type');
  this.res.removeHeader('Content-Length');
  this.res.removeHeader('Transfer-Encoding');
  this.res.end();
};

Responder.prototype.handleRedirect = function(redirect) {
  this.res.statusCode = redirect.status || 301;
  this.res.setHeader('Location', redirect.redirect);
  this.res.setHeader('Content-Type', 'text/html; charset=utf-8');
  this.res.end('Redirecting to ' + redirect.redirect);
  return RSVP.resolve(true);
};

Responder.prototype.handleMiddleware = function(middleware) {
  var self = this;
  return new RSVP.Promise(function(resolve) {
    middleware(self.req, self.res, function() { resolve(false); });
  });
};

Responder.prototype.handleRewrite = function(item) {
  var self = this;
  if (item.rewrite.destination) {
    return self.handleFile({file: item.rewrite.destination});
  }

  for (var key in this.rewriters) {
    if (item.rewrite[key]) {
      return this.rewriters[key](item.rewrite, this).then(function(result) {
        return self._handle(result);
      });
    }
  }
  return RSVP.reject(new Error('Unable to find a matching rewriter for ' + JSON.stringify(item.rewrite)));
};

Responder.prototype.handleData = function(data) {
  this.res.statusCode = data.status || 200;
  this.res.setHeader('Content-Type', data.contentType || 'text/html; charset=utf-8');
  this.res.end(data.data);
  return RSVP.resolve(true);
};

module.exports = Responder;
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var DIR         = './',

        fs          = require('fs'),
        path        = require('path'),
        Util        = require('util-io'),

        mellow      = require('mellow'),
        ponse       = require('ponse'),

        Fs          = {};

        [
            'get',
            'put',
            'patch',
            'delete'
        ].forEach(function(name) {
            Fs[name] = require(DIR + 'fs/' + name);
        });

    /**
     * restafary
     *
     * @param request
     * @param response
     * @param callback
     */
    module.exports = function(options) {
        return middle.bind(null, options || {});
    };

    function middle(options, req, res, next) {
        var name, is, regExp,
            prefix  = options.prefix || '/fs',
            params  = {
                request : req,
                response: res
            };

        name    = ponse.getPathName(req);
        regExp  = new RegExp('^' + prefix),
        is      = regExp.test(name);

        if (!is) {
            next();
        } else {
            name        =
            params.name = name.replace(prefix, '') || '/';

            onFS(params, function(error, options, data) {
                params.gzip = !error;

                if (options.name)
                    params.name = options.name;

                if (options.gzip !== undefined)
                    params.gzip = options.gzip;

                if (options.query)
                    params.query = options.query;

                if (error) {
                    ponse.sendError(error, params);
                } else {
                    if (!data)
                        data = getMsg(name, req);

                    ponse.send(data, params);
                }
            });
        }
    }

    function getMsg(name, req) {
        var msg,
            query   = ponse.getQuery(req),
            method  = req.method.toLowerCase();

        name        = path.basename(name);

        if (method !== 'put') {
            msg     = method;
        } else {
            if (query === 'dir')
                msg = 'make dir';
            else
                msg = 'save';
        }

        msg     = format(msg, name);

        return msg;
    }

    function onFS(params, callback) {
        var path,
            p               = params,
            query           = ponse.getQuery(p.request),
            optionsDefauls  = {
                gzip: false,
                name:'.txt'
            };

        path    = mellow.convertPath(p.name);

        switch (p.request.method) {
        case 'PUT':
            Fs.put(query, path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;

         case 'PATCH':
            Fs.patch(path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;

        case 'GET':
            Fs.get(query, path, function(error, data) {
                onGet({
                    error: error,
                    path: path,
                    query: query,
                    request: p.request,
                    response: p.response,
                    data: data
                }, callback);
            });
            break;

        case 'DELETE':
            Fs.delete(query, path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;
        }
    }

    function onGet(p, callback) {
        var str,
            options = {},
            isFile  = p.error && p.error.code === 'ENOTDIR',
            isStr   = Util.type.string(p.data),
            params  = {
                gzip: true,
                name: p.path,
                request: p.request,
                response: p.response,
            };

        if (isFile) {
            fs.realpath(p.path, function(error, path) {
                if (!error)
                    params.name = path;

                params.gzip = false;
                ponse.sendFile(params);
            });
        } else {
            if (!p.error) {
                p.data.path   = addSlashToEnd(p.name);

                options     = {
                    name    : p.name + '.json',
                    query   : p.query
                };

                if (isStr)
                    str = p.data;
                else
                    str = Util.json.stringify(p.data);
            }

            callback(p.error, options, str);
        }
    }

    function format(msg, name) {
        var status = 'ok';

        if (name)
            name = '("' + name + '")';

        msg = msg + ': ' + status + name;

        return msg;
    }

    function addSlashToEnd(path) {
        var length, isSlash;

        if (path) {
            length  = path.length - 1;
            isSlash = path[length] === '/';

            if (!isSlash)
                path += '/';
        }

        return path;
    }

})();
<commit_msg>chore(restafary) rm comment<commit_after>(function() {
    'use strict';

    var DIR         = './',

        fs          = require('fs'),
        path        = require('path'),
        Util        = require('util-io'),

        mellow      = require('mellow'),
        ponse       = require('ponse'),

        Fs          = {};

        [
            'get',
            'put',
            'patch',
            'delete'
        ].forEach(function(name) {
            Fs[name] = require(DIR + 'fs/' + name);
        });

    module.exports = function(options) {
        return middle.bind(null, options || {});
    };

    function middle(options, req, res, next) {
        var name, is, regExp,
            prefix  = options.prefix || '/fs',
            params  = {
                request : req,
                response: res
            };

        name    = ponse.getPathName(req);
        regExp  = new RegExp('^' + prefix),
        is      = regExp.test(name);

        if (!is) {
            next();
        } else {
            name        =
            params.name = name.replace(prefix, '') || '/';

            onFS(params, function(error, options, data) {
                params.gzip = !error;

                if (options.name)
                    params.name = options.name;

                if (options.gzip !== undefined)
                    params.gzip = options.gzip;

                if (options.query)
                    params.query = options.query;

                if (error) {
                    ponse.sendError(error, params);
                } else {
                    if (!data)
                        data = getMsg(name, req);

                    ponse.send(data, params);
                }
            });
        }
    }

    function getMsg(name, req) {
        var msg,
            query   = ponse.getQuery(req),
            method  = req.method.toLowerCase();

        name        = path.basename(name);

        if (method !== 'put') {
            msg     = method;
        } else {
            if (query === 'dir')
                msg = 'make dir';
            else
                msg = 'save';
        }

        msg     = format(msg, name);

        return msg;
    }

    function onFS(params, callback) {
        var path,
            p               = params,
            query           = ponse.getQuery(p.request),
            optionsDefauls  = {
                gzip: false,
                name:'.txt'
            };

        path    = mellow.convertPath(p.name);

        switch (p.request.method) {
        case 'PUT':
            Fs.put(query, path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;

         case 'PATCH':
            Fs.patch(path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;

        case 'GET':
            Fs.get(query, path, function(error, data) {
                onGet({
                    error: error,
                    path: path,
                    query: query,
                    request: p.request,
                    response: p.response,
                    data: data
                }, callback);
            });
            break;

        case 'DELETE':
            Fs.delete(query, path, p.request, function(error) {
                callback(error, optionsDefauls);
            });
            break;
        }
    }

    function onGet(p, callback) {
        var str,
            options = {},
            isFile  = p.error && p.error.code === 'ENOTDIR',
            isStr   = Util.type.string(p.data),
            params  = {
                gzip: true,
                name: p.path,
                request: p.request,
                response: p.response,
            };

        if (isFile) {
            fs.realpath(p.path, function(error, path) {
                if (!error)
                    params.name = path;

                params.gzip = false;
                ponse.sendFile(params);
            });
        } else {
            if (!p.error) {
                p.data.path   = addSlashToEnd(p.name);

                options     = {
                    name    : p.name + '.json',
                    query   : p.query
                };

                if (isStr)
                    str = p.data;
                else
                    str = Util.json.stringify(p.data);
            }

            callback(p.error, options, str);
        }
    }

    function format(msg, name) {
        var status = 'ok';

        if (name)
            name = '("' + name + '")';

        msg = msg + ': ' + status + name;

        return msg;
    }

    function addSlashToEnd(path) {
        var length, isSlash;

        if (path) {
            length  = path.length - 1;
            isSlash = path[length] === '/';

            if (!isSlash)
                path += '/';
        }

        return path;
    }

})();
<|endoftext|>


<commit_before>/* jshint node:true, unused:true */
"use strict";

var url = require('url');

var _ = require('lodash');
var rest = require('restler');
var Q    = require('q');

var restler_q = ['request', 'get','patch','post','put','del','head','json','postJson','putJson'].reduce(function(memo, method) {
    var underlying = rest[method];
    if(underlying) {
        memo[method] = wrapMethod(underlying);
        memo.spread[method] = wrapMethod(underlying, true);
    }
    return memo;
}, {
    spread: {},
    Request: rest.Request,
    parsers: rest.parsers,
    file: rest.file,
    data: rest.data,
    Service: Service,
    service: service
});

module.exports = restler_q;

var STATUS_CODES = {
    'Unauthorized': 401,
    'Forbidden': 403,
    'Not Found': 404,
    'Internal Server Error': 500,
    'Not Implemented': 501,
    'Service Unavailable': 503,
};

function str2error(str, req) {
    var err = new Error(str);
    err.code = STATUS_CODES[str];
    err.statusCode = err.code;
    if (req) { err.url = url.format(req.url); }
    return err;
}

function wrap(r, spread) {
    var defer = Q.defer();

    r.on('success', function(result, response) {
        if(spread) { return defer.resolve([ result, response ]); }
        defer.resolve(result);
    });

    r.on('timeout', function(ms) {
        var err = new Error('ETIMEDOUT');
        err.code = 'ETIMEDOUT';
        err.errno = 'ETIMEDOUT';
        err.statusCode = 408;
        err.syscall = 'connect';
        err.timeout = ms;
        err.url = url.format(r.url);
        defer.reject(err);
    });

    r.on('fail', function(err, response) {
        if(spread) { err.response = response; }
        if (typeof(err) === 'string') { err = str2error(err, r); }
        if (!err.url) { err.url = url.format(r.url); }
        defer.reject(err);
    });

    r.on('error', function(err, response) {
        if(spread) { err.response = response; }
        if (typeof(err) === 'string') { err = str2error(err, r); }
        if (!err.url) { err.url = url.format(r.url); }
        defer.reject(err);
    });

    r.on('abort', function() {
        var err = new Error('Operation aborted');
        err.url = url.format(r.url);
        defer.reject(err);
    });

    return defer.promise;
}

function wrapMethod(method, spread) {
    return function() {
        var request = method.apply(rest, arguments);
        return wrap(request, spread);
    };
}

function mixin(target, source) {
    source = source || {};
    Object.keys(source).forEach(function(key) {
        target[key] = source[key];
    });

    return target;
}

function Service(defaults) {
    defaults = defaults || {};
    if (defaults.baseURL) {
        this.baseURL = defaults.baseURL;
        delete defaults.baseURL;
    }
    this.defaults = defaults;
}

var url = require('url');

mixin(Service.prototype, {
    request: function(path, options) {
        return restler_q.request(this._url(path), this._withDefaults(options));
    },
    get: function(path, options) {
        return restler_q.get(this._url(path), this._withDefaults(options));
    },
    head: function(path, options) {
        return restler_q.head(this._url(path), this._withDefaults(options));
    },
    patch: function(path, options) {
        return restler_q.patch(this._url(path), this._withDefaults(options));
    },
    put: function(path, options) {
        return restler_q.put(this._url(path), this._withDefaults(options));
    },
    post: function(path, options) {
        return restler_q.post(this._url(path), this._withDefaults(options));
    },
    json: function(path, options) {
        return restler_q.json(this._url(path), this._withDefaults(options));
    },
    postJson: function(path, options) {
        return restler_q.postJson(this._url(path), this._withDefaults(options));
    },
    putJson: function(path, options) {
        return restler_q.putJson(this._url(path), this._withDefaults(options));
    },
    del: function(path, options) {
        return restler_q.del(this._url(path), this._withDefaults(options));
    },
    _url: function(path) {
        if (this.baseURL){
            return url.resolve(this.baseURL, path);
        }
        else {
            return path;
        }
    },
    _withDefaults: function(options) {
        var opts = mixin({}, this.defaults);
        return mixin(opts, options);
    }
});

function service(constructor, defaults, methods) {
    constructor.prototype = new Service(defaults || {});
    mixin(constructor.prototype, methods);
    return constructor;
}
<commit_msg>Remove unintentional reference to lodash library.<commit_after>/* jshint node:true, unused:true */
"use strict";

var url = require('url');

var rest = require('restler');
var Q    = require('q');

var restler_q = ['request', 'get','patch','post','put','del','head','json','postJson','putJson'].reduce(function(memo, method) {
    var underlying = rest[method];
    if(underlying) {
        memo[method] = wrapMethod(underlying);
        memo.spread[method] = wrapMethod(underlying, true);
    }
    return memo;
}, {
    spread: {},
    Request: rest.Request,
    parsers: rest.parsers,
    file: rest.file,
    data: rest.data,
    Service: Service,
    service: service
});

module.exports = restler_q;

var STATUS_CODES = {
    'Unauthorized': 401,
    'Forbidden': 403,
    'Not Found': 404,
    'Internal Server Error': 500,
    'Not Implemented': 501,
    'Service Unavailable': 503,
};

function str2error(str, req) {
    var err = new Error(str);
    err.code = STATUS_CODES[str];
    err.statusCode = err.code;
    if (req) { err.url = url.format(req.url); }
    return err;
}

function wrap(r, spread) {
    var defer = Q.defer();

    r.on('success', function(result, response) {
        if(spread) { return defer.resolve([ result, response ]); }
        defer.resolve(result);
    });

    r.on('timeout', function(ms) {
        var err = new Error('ETIMEDOUT');
        err.code = 'ETIMEDOUT';
        err.errno = 'ETIMEDOUT';
        err.statusCode = 408;
        err.syscall = 'connect';
        err.timeout = ms;
        err.url = url.format(r.url);
        defer.reject(err);
    });

    r.on('fail', function(err, response) {
        if(spread) { err.response = response; }
        if (typeof(err) === 'string') { err = str2error(err, r); }
        if (!err.url) { err.url = url.format(r.url); }
        defer.reject(err);
    });

    r.on('error', function(err, response) {
        if(spread) { err.response = response; }
        if (typeof(err) === 'string') { err = str2error(err, r); }
        if (!err.url) { err.url = url.format(r.url); }
        defer.reject(err);
    });

    r.on('abort', function() {
        var err = new Error('Operation aborted');
        err.url = url.format(r.url);
        defer.reject(err);
    });

    return defer.promise;
}

function wrapMethod(method, spread) {
    return function() {
        var request = method.apply(rest, arguments);
        return wrap(request, spread);
    };
}

function mixin(target, source) {
    source = source || {};
    Object.keys(source).forEach(function(key) {
        target[key] = source[key];
    });

    return target;
}

function Service(defaults) {
    defaults = defaults || {};
    if (defaults.baseURL) {
        this.baseURL = defaults.baseURL;
        delete defaults.baseURL;
    }
    this.defaults = defaults;
}

var url = require('url');

mixin(Service.prototype, {
    request: function(path, options) {
        return restler_q.request(this._url(path), this._withDefaults(options));
    },
    get: function(path, options) {
        return restler_q.get(this._url(path), this._withDefaults(options));
    },
    head: function(path, options) {
        return restler_q.head(this._url(path), this._withDefaults(options));
    },
    patch: function(path, options) {
        return restler_q.patch(this._url(path), this._withDefaults(options));
    },
    put: function(path, options) {
        return restler_q.put(this._url(path), this._withDefaults(options));
    },
    post: function(path, options) {
        return restler_q.post(this._url(path), this._withDefaults(options));
    },
    json: function(path, options) {
        return restler_q.json(this._url(path), this._withDefaults(options));
    },
    postJson: function(path, options) {
        return restler_q.postJson(this._url(path), this._withDefaults(options));
    },
    putJson: function(path, options) {
        return restler_q.putJson(this._url(path), this._withDefaults(options));
    },
    del: function(path, options) {
        return restler_q.del(this._url(path), this._withDefaults(options));
    },
    _url: function(path) {
        if (this.baseURL){
            return url.resolve(this.baseURL, path);
        }
        else {
            return path;
        }
    },
    _withDefaults: function(options) {
        var opts = mixin({}, this.defaults);
        return mixin(opts, options);
    }
});

function service(constructor, defaults, methods) {
    constructor.prototype = new Service(defaults || {});
    mixin(constructor.prototype, methods);
    return constructor;
}
<|endoftext|>